/*
 * Copyright (c) 2023 CHANGLEI. All rights reserved.
 */

package com.graspyun.plugin.tverify

//noinspection SuspiciousImport

import android.R
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.pm.ActivityInfo
import android.content.res.Configuration
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.RectF
import android.graphics.Typeface
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.graphics.drawable.StateListDrawable
import android.os.Build
import android.os.Handler
import android.os.Looper
import android.view.Gravity
import android.view.Surface
import android.view.View
import android.view.WindowManager
import android.widget.Button
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.RelativeLayout
import android.widget.TextView
import io.flutter.FlutterInjector
import io.flutter.plugin.common.MethodChannel

/**
 * Created by changlei on 2023/8/15.
 * <p>
 * View
 */
fun toView(context: Context, channel: MethodChannel, map: Map<*, *>): View {
    return configView(
        when (map["type"] as String) {
            "UITextView" -> toTextView(context, map)
            "UIButton" -> toButton(context, map)
            "UIImageView" -> toImageView(context, map)
            "UIViewGroup" -> toViewGroup(context, channel, map)
            else -> View(context)
        }, channel, map
    )
}

private fun configView(customView: View, channel: MethodChannel, map: Map<*, *>): View {
    val context = customView.context
    // 设置背景颜色
    val backgroundColor = map["backgroundColor"] as Map<*, *>?
    if (backgroundColor != null) {
        customView.setBackgroundColor((backgroundColor["value"] as Long).toInt())
    }

    // 背景图片
    val background = map["background"] as Map<*, *>?
    if (background != null) {
        customView.background = background.toDrawable(context)
    }

    // 位置
    val left = map["left"] as Number
    val top = map["top"] as Number
    val width = map["width"] as Number
    val height = map["height"] as Number
    val layoutParams = RelativeLayout.LayoutParams(
        RelativeLayout.LayoutParams.WRAP_CONTENT,
        RelativeLayout.LayoutParams.WRAP_CONTENT
    )
    layoutParams.leftMargin = dp2Pix(context, left)
    layoutParams.topMargin = dp2Pix(context, top)
    if (width.toDouble() > 0) {
        layoutParams.width = dp2Pix(context, width)
    } else if (width.toDouble() == Double.POSITIVE_INFINITY || width.toInt() == -1) {
        layoutParams.width = RelativeLayout.LayoutParams.MATCH_PARENT
    }
    if (height.toDouble() > 0) {
        layoutParams.height = dp2Pix(context, height)
    } else if (height.toDouble() == Double.POSITIVE_INFINITY || height.toInt() == -1) {
        layoutParams.height = RelativeLayout.LayoutParams.MATCH_PARENT
    }
    customView.layoutParams = layoutParams

    // 内边距
    (map["padding"] as Map<*, *>?)?.apply {
        customView.setPadding(
            dp2Pix(context, this["left"] as Number),
            dp2Pix(context, this["top"] as Number),
            dp2Pix(context, this["right"] as Number),
            dp2Pix(context, this["bottom"] as Number),
        )
    }

    // 点击事件 id
    if (map["isClickEnable"] == true) {
        val jsonMap = mutableMapOf<String, Any>()
        jsonMap["id"] = map["id"] as String
        customView.setOnClickListener { runMainThread(jsonMap, channel) }
    }

    return customView
}

private fun configTextView(customView: TextView, map: Map<*, *>): View {
    val context = customView.context

    // 设置text
    val title = map["title"] as String?
    customView.text = title

    // 设置字体颜色
    val titleColor = map["titleColor"] as Map<*, *>?
    if (titleColor != null) {
        customView.setTextColor((titleColor["value"] as Long).toInt())
    }

    // 设置字体大小
    val font = map["titleFont"] as Map<*, *>?
    if (font != null) {
        val titleFont = font["fontSize"] as Double
        if (titleFont > 0) {
            customView.textSize = titleFont.toFloat()
        }
        val fontWeight = font["fontWeight"] as Int?
        if (fontWeight != null) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                customView.typeface = Typeface.create(null, fontWeight, false)
            } else {
                customView.typeface = Typeface.defaultFromStyle(
                    if (fontWeight >= 700) Typeface.BOLD else Typeface.NORMAL
                )
            }
        }
    }

    // 下划线
    val isShowUnderline = map["isShowUnderline"] as Boolean
    if (isShowUnderline) {
        customView.paint.flags = Paint.UNDERLINE_TEXT_FLAG //下划线
        customView.paint.isAntiAlias = true //抗锯齿
    }

    // 设置对齐方式
    val alignment = map["textAlignment"]
    if (alignment != null) {
        val textAlignment = alignment as Int
        val gravity: Int = getAlignmentFromString(textAlignment)
        customView.gravity = gravity
    }

    val isSingleLine = map["isSingleLine"] as Boolean
    customView.isSingleLine = isSingleLine //设置是否单行显示，多余的就 ...
    val lines = map["lines"] as Int
    customView.setLines(lines) //设置行数

    val leftDrawable = map["leftImage"] as Map<*, *>?
    val topDrawable = map["topImage"] as Map<*, *>?
    val rightDrawable = map["rightImage"] as Map<*, *>?
    val bottomDrawable = map["bottomImage"] as Map<*, *>?
    customView.setCompoundDrawablesWithIntrinsicBounds(
        leftDrawable?.toDrawable(context),
        topDrawable?.toDrawable(context),
        rightDrawable?.toDrawable(context),
        bottomDrawable?.toDrawable(context),
    )
    (map["imagePadding"] as Number?)?.toDouble()?.apply {
        customView.compoundDrawablePadding = dp2Pix(context, this)
    }
    return customView
}

private fun toTextView(context: Context, map: Map<*, *>): View {
    return configTextView(TextView(context), map)
}

/**
 * 添加自定义 button
 */
private fun toButton(context: Context, map: Map<*, *>): View {
    val customView = configTextView(Button(context), map) as Button

    // 设置背景图（只支持 button 设置）
    val normalImage = map["btnNormalImage"] as Map<*, *>?
    val pressedImage = map["btnPressedImage"] as Map<*, *>?
    if (normalImage != null) {
        setButtonSelector(context, customView, normalImage, pressedImage ?: normalImage)
    } else {
        customView.background = null
    }
    return customView
}

private fun toImageView(context: Context, map: Map<*, *>): View {
    val customView = ImageView(context)
    (map["src"] as Map<*, *>?)?.apply {
        customView.setImageBitmap(toBitmap(context))
    }
    (map["fit"] as Int?)?.apply {
        customView.scaleType = when (BoxFit.values()[this]) {
            BoxFit.fill -> ImageView.ScaleType.FIT_XY
            BoxFit.contain -> ImageView.ScaleType.CENTER_INSIDE
            BoxFit.cover -> ImageView.ScaleType.CENTER_CROP
            BoxFit.fitWidth -> ImageView.ScaleType.FIT_XY
            BoxFit.fitHeight -> ImageView.ScaleType.FIT_XY
            BoxFit.none -> ImageView.ScaleType.CENTER
            BoxFit.scaleDown -> ImageView.ScaleType.FIT_END
        }
    }
    return customView
}

private fun toViewGroup(context: Context, channel: MethodChannel, map: Map<*, *>): View {
    val customView = FrameLayout(context)
    (map["children"] as List<*>?)?.apply {
        for (child in this) {
            customView.addView(toView(context, channel, child as Map<*, *>))
        }
    }
    return customView
}

private fun runMainThread(map: Map<String, Any>, channel: MethodChannel) {
    val handler = Handler(Looper.getMainLooper())
    handler.post {
        channel.invokeMethod("onClickListener", map)
    }
}

/**
 * 获取对齐方式
 */
private fun getAlignmentFromString(alignment: Int?): Int {
    var a = 0
    if (alignment != null) {
        a = when (alignment) {
            0 -> Gravity.START
            3 -> Gravity.TOP
            2 -> Gravity.END
            4 -> Gravity.BOTTOM
            1 -> Gravity.CENTER
            else -> Gravity.NO_GRAVITY
        }
    }
    return a
}

/**
 * 像素转化成 pix
 */
private fun dp2Pix(context: Context, dp: Number): Int {
    return try {
        val density = context.resources.displayMetrics.density
        ((dp.toDouble()) * density + 0.5f).toInt()
    } catch (e: Exception) {
        dp.toInt()
    }
}

private fun setButtonSelector(
    context: Context,
    button: Button,
    normalImage: Map<*, *>,
    pressImage: Map<*, *>,
) {
    val drawable = StateListDrawable()
    val normalDrawable = normalImage.toDrawable(context)
    val selectDrawable = pressImage.toDrawable(context)

    // 未选中
    drawable.addState(intArrayOf(-R.attr.state_pressed), normalDrawable)
    //选中
    drawable.addState(intArrayOf(R.attr.state_pressed), selectDrawable)
    button.background = drawable
}

@Suppress("EnumEntryName")
private enum class BoxFit {
    fill,
    contain,
    cover,
    fitWidth,
    fitHeight,
    none,
    scaleDown
}

private fun Map<*, *>.toBitmap(context: Context): Bitmap {
    val data = this["data"]
    val `package` = this["package"] as String?
    val size = this["size"] as Map<*, *>?
    val radius = this["radius"] as Double?
    return when (this["type"]) {
        "name" -> BitmapFactory.decodeResource(
            context.resources,
            context.getDrawableId(data as String)
        )

        "asset" -> loadAsset(context, data as String, `package`)
        "color" -> toColorBitmap(context, data as Map<*, *>, size!!, radius!!)
        else -> (data as ByteArray).toBitmap()
    }
}

private fun ByteArray.toBitmap(): Bitmap {
    return BitmapFactory.decodeByteArray(this, 0, size)
}

private fun Map<*, *>.toDrawable(context: Context): Drawable {
    return BitmapDrawable(context.resources, toBitmap(context))
}

@Suppress("NAME_SHADOWING")
private fun toColorBitmap(context: Context, color: Map<*, *>, size: Map<*, *>, radius: Double): Bitmap {
    return toColorBitmap(context, (color["value"] as Long).toInt(), size, radius)
}

@Suppress("NAME_SHADOWING")
private fun toColorBitmap(context: Context, color: Int, size: Map<*, *>, radius: Double): Bitmap {
    val width = dp2Pix(context, (size["width"] as Number).toFloat())
    val height = dp2Pix(context, (size["height"] as Number).toFloat())
    val radius = dp2Pix(context, radius.toFloat()).toFloat()
    val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
    val canvas = Canvas(bitmap)

    val paint = Paint(Paint.ANTI_ALIAS_FLAG)
    paint.color = color

    val rect = RectF(0f, 0f, width.toFloat(), height.toFloat())
    canvas.drawRoundRect(rect, radius, radius, paint)
    return bitmap
}

internal fun loadAsset(context: Context, name: String, `package`: String? = null): Bitmap {
    val assets = context.assets
    val flutterLoader = FlutterInjector.instance().flutterLoader()
    val asset = if (`package` == null) {
        flutterLoader.getLookupKeyForAsset(name)
    } else {
        flutterLoader.getLookupKeyForAsset(name, `package`)
    }
    val fileDescriptor = assets.openFd(asset)
    return BitmapFactory.decodeStream(fileDescriptor.createInputStream())
}

@SuppressLint("ViewConstructor")
@Suppress("DEPRECATION")
internal class RootView(context: Context, private val arguments: Map<*, *>) :
    RelativeLayout(context) {
    private var orientation = ActivityInfo.SCREEN_ORIENTATION_LOCKED

    override fun onAttachedToWindow() {
        super.onAttachedToWindow()
        orientation = getScreenOrientation(context)
        val statusBarBgColor = arguments["statusBarBgColor"] as Int?
        val statusBarTextColor = arguments["statusBarTextColor"] as Boolean?
        ((parent as? View)?.context as? Activity)?.apply {
            setTranslucentStatusBar(this, statusBarBgColor, statusBarTextColor)
        }
    }

    override fun onConfigurationChanged(newConfig: Configuration?) {
        super.onConfigurationChanged(newConfig)
        if (orientation == getScreenOrientation(context)) {
            return
        }
        ((parent as? View)?.context as? Activity)?.apply {
            requestedOrientation = orientation
        }
    }

    private fun getScreenOrientation(context: Context): Int {
        val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
        return when (windowManager.defaultDisplay.rotation) {
            Surface.ROTATION_0 -> ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
            Surface.ROTATION_180 -> ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT
            Surface.ROTATION_90 -> ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
            Surface.ROTATION_270 -> ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
            else -> ActivityInfo.SCREEN_ORIENTATION_LOCKED
        }
    }

    private fun setTranslucentStatusBar(
        activity: Activity,
        statusBarColor: Int?,
        statusBarTextColor: Boolean?
    ) {
        val window = activity.window
        window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS or WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION)
        var systemUiVisibility = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or SYSTEM_UI_FLAG_LAYOUT_STABLE
        window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
        window.statusBarColor = statusBarColor ?: Color.TRANSPARENT
        systemUiVisibility =
            if (statusBarTextColor == true && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
            } else {
                systemUiVisibility or View.SYSTEM_UI_FLAG_VISIBLE
            }
        rootView.systemUiVisibility = systemUiVisibility
    }
}

internal fun Context.getDrawableId(name: String): Int {
    return resources.getIdentifier(name, "drawable", packageName)
}

internal fun Context.getLayoutId(name: String): Int {
    return resources.getIdentifier(name, "layout", packageName)
}

internal fun Context.getStyleId(name: String): Int {
    return resources.getIdentifier(name, "style", packageName)
}
